﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;

namespace Xceed.Silverlight.Data
{
  internal abstract class DataEnumeratorBase : IDataEnumerator
  {
    #region SyncRoot Protected Property

    protected object SyncRoot
    {
      get
      {
        return m_syncRoot;
      }
    }

    private readonly object m_syncRoot = new object();

    #endregion

    #region DataChanged Event

    public event EventHandler<DataChangedEventArgs> DataChanged;

    protected abstract IEnumerable<DataSourceChangedEventArgs> TransformDataSourceChangedEventArgs( DataSourceContext context, DataSourceChangedEventArgs e );

    protected void RaiseDataReplaced( object oldItem, object newItem )
    {
      if( m_disposed )
        return;

      // We copy the event handler into a temporary variable in case the
      // event handler is set to null by another thread.
      EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

      if( dataChanged != null )
      {
        DataChangedEventArgs e = new DataChangedEventArgs( DataChangedAction.Replace, newItem, oldItem );

        dataChanged.Invoke( this, e );
      }
    }

    protected void RaiseDataAdd( object newItem )
    {
      if( m_disposed )
        return;

      // We copy the event handler into a temporary variable in case the
      // event handler is set to null by another thread.
      EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

      if( dataChanged != null )
      {
        DataChangedEventArgs e = new DataChangedEventArgs( DataChangedAction.Add, newItem );

        dataChanged.Invoke( this, e );
      }
    }

    protected void RaiseDataRemoved( object oldItem, SourcePosition removePosition, SourcePosition newCurrentPosition )
    {
      if( m_disposed )
        return;

      // We copy the event handler into a temporary variable in case the
      // event handler is set to null by another thread.
      EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

      if( dataChanged != null )
      {
        DataChangedEventArgs e = new DataChangedEventArgs( DataChangedAction.Remove, oldItem, removePosition, newCurrentPosition );

        dataChanged.Invoke( this, e );
      }
    }

    protected void RaiseDataReset()
    {
      if( m_disposed )
        return;

      // We copy the event handler into a temporary variable in case the
      // event handler is set to null by another thread.
      EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

      if( dataChanged != null )
      {
        DataChangedEventArgs e = new DataChangedEventArgs( DataChangedAction.Reset );

        dataChanged.Invoke( this, e );
      }
    }

    protected void RaiseDataItemChanged( ItemChangedInfo itemChangedInfo )
    {
      if( m_disposed )
        return;

      // We copy the event handler into a temporary variable in case the
      // event handler is set to null by another thread.
      EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

      if( dataChanged != null )
      {
        DataChangedEventArgs e = new DataChangedEventArgs( itemChangedInfo );

        dataChanged.Invoke( this, e );
      }
    }

    protected void RaiseDataChanged( DataChangedEventArgs e )
    {
      if( m_disposed )
        return;

      if( e != null )
      {
        // We copy the event handler into a temporary variable in case the
        // event handler is set to null by another thread.
        EventHandler<DataChangedEventArgs> dataChanged = this.DataChanged;

        if( dataChanged != null )
        {
          dataChanged.Invoke( this, e );
        }
      }
    }

    IEnumerable<DataSourceChangedEventArgs> IDataEnumerator.TransformDataSourceChangedEventArgs( DataSourceContext context, DataSourceChangedEventArgs e )
    {
      return this.TransformDataSourceChangedEventArgs( context, e );
    }

    #endregion

    protected void CheckMoveAndFetchParameters( long expectedMoveCount, int expectedFetchCount )
    {
      if( ( expectedMoveCount == 0 ) && ( expectedFetchCount == 0 ) )
        throw new InvalidOperationException( "expectedMoveCount and expectedFetchCount must be non-zero" );
    }

    #region IDisposable Members

    public void Dispose()
    {
      lock( this.SyncRoot )
      {
        this.Dispose( true );
        GC.SuppressFinalize( this );
      }
    }

    protected virtual void Dispose( bool disposing )
    {
      if( disposing )
      {
        this.DataChanged = null;
      }

      m_disposed = true;
    }

    ~DataEnumeratorBase()
    {
      lock( this.SyncRoot )
      {
        this.Dispose( false );
      }
    }

    #endregion

    #region Private Fields

    private bool m_disposed; //false

    #endregion
  }
}
